package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.listener.ReadListener;
import com.google.common.collect.Lists;
import com.sc.nft.dao.*;
import com.sc.nft.entity.*;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.entity.vo.*;
import com.sc.nft.enums.PointsExchangeCollectionStatusEnum;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.enums.UserConsensusTypeEnums;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.sup.Result;
import com.sc.nft.util.BigDecimalUtils;
import com.sc.nft.util.WeChatUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import com.sc.nft.service.UserConsensusService;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户共识度表服务接口实现
 *
 * @author zxy
 * @description 由 Mybatisplus Code Generator 创建
 * @since 2024-08-24 21:56:44
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class UserConsensusServiceImpl implements UserConsensusService {
    private final UserConsensusDao userConsensusDao;
    private final ExitConsensusUserDao exitConsensusUserDao;
    private final DigitalCollectionDao digitalCollectionDao;
    private final Redisson redisson;
    private final FilterIncomeListDao filterIncomeListDao;
    private final UserCollectionConsensusDao userCollectionConsensusDao;
    private final UserInfoDao userInfoDao;
    private final UserCollectionDao userCollectionDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void adjustConsensusService(Long userId, Long collectionId, BigDecimal consensusNum, UserConsensusTypeEnums type, String remark, Boolean beforeSmelt) {

        Assert.notNull(userId, () -> new GlobalRunTimeException("用户不能为空"));
        if (filterIncomeListDao.checkListIsFilterAccount(Lists.newArrayList(6L, 7L), userId)) {
            return;
        }
        Assert.notNull(consensusNum, () -> new GlobalRunTimeException("共识度不能为空"));
        if (NumberUtil.equals(consensusNum, BigDecimal.ZERO)) {
            return;
        }
        if (type.getIsAdd() == 1) {
            Assert.isTrue(NumberUtil.isGreater(consensusNum, BigDecimal.ZERO), () -> new GlobalRunTimeException("共识度必须为正数"));
        }
        if (type.getIsAdd() == -1) {
            Assert.isTrue(NumberUtil.isLess(consensusNum, BigDecimal.ZERO), () -> new GlobalRunTimeException("共识度必须为负数"));
        }
        Assert.notNull(type, () -> new GlobalRunTimeException("必须输入操作类型"));
        ExitConsensusUser exitConsensusUser = exitConsensusUserDao.getByUserId(userId);
        if (ObjectUtil.isNotNull(exitConsensusUser) && exitConsensusUser.getStatus()) {
            log.warn("用户{}非共识区用户", userId);
            return;
        }
        RLock lock = redisson.getLock(RedisKeyEnum.CONSENSUS_LOCK.getKey() + userId);
        try {
            boolean res = lock.tryLock(3, TimeUnit.SECONDS);
            if (res) {
                UserCollectionConsensus userCollectionConsensus = getUserCollectionConsensus(userId, collectionId);

                if (type == UserConsensusTypeEnums.SMELT_OUT && beforeSmelt) {
                    UserConsensus userConsensus = userConsensusDao.getUserConsensus(userId);
                    consensusNum = consensusNum.multiply(userConsensus.getSmeltOutRatio());
                }
                Assert.isTrue(NumberUtil.isGreaterOrEqual(userCollectionConsensus.getConsensusNum().add(consensusNum), BigDecimal.ZERO), () -> new GlobalRunTimeException("共识度不足"));
                if (UserConsensusTypeEnums.CHANGE_INTO == type) {
                    DigitalCollection ecologyCollection = digitalCollectionDao.getEcologyCollectionById(collectionId);
                    Assert.notNull(ecologyCollection, () -> new GlobalRunTimeException("非生态藏品不允许转入"));
                    UserConsensus userConsensus = userConsensusDao.getUserConsensus(userId);
                    Assert.isTrue(NumberUtil.isGreaterOrEqual(userConsensus.getConsensusNum(), consensusNum), () -> new GlobalRunTimeException("通用共识度不足"));
                    userConsensusDao.subConsensus(userConsensus.getUserId(), consensusNum);
                    UserConsensusLog userConsensusLog = new UserConsensusLog();
                    userConsensusLog.setUserId(userId);
                    userConsensusLog.setType(UserConsensusTypeEnums.CHANGE_OUT);
                    userConsensusLog.setCollectionId(0L);
                    userConsensusLog.setConsensusNum(consensusNum.negate());
                    userConsensusLog.setRemark(userConsensusLog.getType().getDescription().concat(ecologyCollection.getFirstTitle()));
                    userConsensusLog.setBeforeNum(userConsensus.getConsensusNum());
                    userConsensusLog.setAfterNum(userConsensus.getConsensusNum().subtract(consensusNum));
                    userConsensusLog.insert();
                }
                UserConsensusLog userConsensusLog = new UserConsensusLog();
                userConsensusLog.setUserId(userId);
                userConsensusLog.setType(type);
                userConsensusLog.setCollectionId(collectionId);
                userConsensusLog.setConsensusNum(consensusNum);
                userConsensusLog.setRemark(StrUtil.isNotBlank(remark) ? type.getDescription().concat(remark) : type.getDescription());
                userConsensusLog.setBeforeNum(userCollectionConsensus.getConsensusNum());
                userConsensusLog.setAfterNum(userCollectionConsensus.getConsensusNum().add(consensusNum));
                userConsensusLog.insert();
                userCollectionConsensusDao.updateConsensus(userCollectionConsensus.getId(), consensusNum);
            } else {
                throw new GlobalRunTimeException(ErrorCode.LATER_TRY);
            }
        } catch (InterruptedException e) {
            throw new GlobalRunTimeException(ErrorCode.LATER_TRY);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public UserConsensus getByUserId(Long userId) {
        return userConsensusDao.getUserConsensus(userId);
    }


    public UserCollectionConsensus getUserCollectionConsensus(Long userId, Long collectionId) {
        UserCollectionConsensus userCollectionConsensus = userCollectionConsensusDao.getBuyUserIdAndCollectionId(userId, collectionId);
        if (ObjectUtil.isNull(userCollectionConsensus)) {
            userCollectionConsensus = new UserCollectionConsensus();
            userCollectionConsensus.setUserId(userId);
            userCollectionConsensus.setCollectionId(collectionId);
            userCollectionConsensus.setConsensusNum(BigDecimal.ZERO);
            userCollectionConsensus.insert();
        }
        return userCollectionConsensus;
    }

    /**
     * admin用户共识度列表
     *
     * @param page
     * @param userTel
     * @return
     */
    @Override
    public Page<UserConsensusPageVO> getUserConsensusAdminPage(Page page, String userTel) {
        return userConsensusDao.getUserConsensusAdminPage(page, userTel);
    }

    /**
     * 用户生态藏品共识度
     *
     * @param userId
     * @return
     */
    @Override
    public List<UserCollectionConsensusListVO> getUserCollectionConsensusAdminList(Long userId) {
        List<UserCollectionConsensus> userCollectionConsensusList = userCollectionConsensusDao.getUserCollectionConsensusListByUserId(userId);
        List<UserCollectionConsensusListVO> userCollectionConsensusListVOS = BeanUtil.copyToList(userCollectionConsensusList, UserCollectionConsensusListVO.class);
        for (UserCollectionConsensusListVO userCollectionConsensusListVO : userCollectionConsensusListVOS) {
            DigitalCollection digitalCollection = digitalCollectionDao.getById(userCollectionConsensusListVO.getCollectionId());
            userCollectionConsensusListVO.setCollectionName(digitalCollection.getFirstTitle());
        }
        return userCollectionConsensusListVOS;
    }

    /**
     * 解析文件
     *
     * @param file
     * @return
     */
    @Override
    @SneakyThrows
    public UserCollectionConsensusExcelParsingVO excelPassing(MultipartFile file, Long collectionId) {
        UserCollectionConsensusExcelParsingVO vo = new UserCollectionConsensusExcelParsingVO();
        // 读取文档.
        ExcelReaderBuilder read = EasyExcel.read(file.getInputStream(), UserCollectionConsensusExcelParsingListVO.class, new ReadListener<UserCollectionConsensusExcelParsingListVO>() {
            @Override
            public void invoke(UserCollectionConsensusExcelParsingListVO data, AnalysisContext context) {
                data.setUserTel(data.getUserTel().trim());
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {

            }
        });
        // 结果集
        List<UserCollectionConsensusExcelParsingListVO> voList = read.sheet().doReadSync();
        if (CollUtil.isEmpty(voList)) {
            throw new GlobalRunTimeException("发放数据为空");
        }
        if (voList.size() > 200) {
            throw new GlobalRunTimeException("发放数据超过200条");
        }
        vo.prepositionVerify(voList);

        // 把voList中的手机号转成集合
        List<String> userTelList = voList.stream().map(UserCollectionConsensusExcelParsingListVO::getUserTel).collect(Collectors.toList());
        // 根据手机号,在用户表中查询用户信息,在进行组装.
        List<UserCollectionConsensusExcelParsingListVO> userInfoList = userInfoDao.userTelByConsensus(userTelList);
//        if (CollUtil.isEmpty(userInfoList)) {
//            throw new GlobalRunTimeException("发放数据为空");
//        }
        vo.compare(voList,userInfoList);

        List<Long> userIdList = userInfoList.stream().map(UserCollectionConsensusExcelParsingListVO::getUserId).distinct().collect(Collectors.toList());
        Map<Long, String> usetTelMap = userInfoList.stream().collect(Collectors.toMap(UserCollectionConsensusExcelParsingListVO::getUserId, UserCollectionConsensusExcelParsingListVO::getUserTel));
        //查询是否在共识度
        List<ExitConsensusUser> exitConsensusUserList = exitConsensusUserDao.getByUserIdList(userIdList);
        if (!CollectionUtil.isEmpty(exitConsensusUserList)) {
            for (ExitConsensusUser exitConsensusUser : exitConsensusUserList) {
                if (ObjectUtil.isNotNull(exitConsensusUser) && exitConsensusUser.getStatus()) {
                    throw new GlobalRunTimeException(usetTelMap.get(exitConsensusUser.getUserId()) + ":非共识区用户");
                }
            }
        }
        //查询用户该藏品共识度
        List<UserCollectionConsensus> buyUserIdListAndCollectionId = userCollectionConsensusDao.getBuyUserIdListAndCollectionId(userIdList, collectionId);
        if (!CollUtil.isEmpty(buyUserIdListAndCollectionId)) {
            Map<Long, BigDecimal> collectionConsensusList = buyUserIdListAndCollectionId.stream().collect(Collectors.toMap(UserCollectionConsensus::getUserId, UserCollectionConsensus::getConsensusNum));
            for (UserCollectionConsensusExcelParsingListVO consensusExcelParsingListVO : userInfoList) {
                consensusExcelParsingListVO.setNowConsensusNum(collectionConsensusList.getOrDefault(consensusExcelParsingListVO.getUserId(), BigDecimal.ZERO));
            }
        }
        vo.setExcelList(userInfoList);
        return vo;
    }

    /**
     * 每周共识度调整
     */
    @Override
    public void consensusAdjustmentTask() {
        // 获取所有需要调整的用户共识度
        List<UserCollectionConsensus> userCollectionConsensusesList = userCollectionConsensusDao.synchronousConsensusDegreeList();
        for (UserCollectionConsensus userCollectionConsensus : userCollectionConsensusesList) {
            // 拥有的数量
            Integer consensusQuantity = userCollectionDao.consensusQuantity(userCollectionConsensus.getUserId(), userCollectionConsensus.getCollectionId());
            try {
                UserCollectionConsensus collectionConsensus = userCollectionConsensusDao.getById(userCollectionConsensus.getId());
                if (BigDecimalUtils.compare(collectionConsensus.getConsensusNum(), consensusQuantity)) {
                    adjustConsensusService(userCollectionConsensus.getUserId(), userCollectionConsensus.getCollectionId(), BigDecimalUtils.subtract(consensusQuantity,collectionConsensus.getConsensusNum()),UserConsensusTypeEnums.SYSTEM,UserConsensusTypeEnums.SYSTEM.getDescription(),null);
                }
            } catch (Exception e) {
                WeChatUtil.sendLiGenWeChatMessage(StrUtil.format("每周共识度调整失败 记录id：{},异常:{}", userCollectionConsensus.getId(), e.getMessage()));
                log.error("每周共识度调整失败 记录id：{},异常:{}", userCollectionConsensus.getId(), e.getMessage());
            }
        }
    }
}